這篇是 k8s pods 上面的特定的用法,為了要讓pod 部署到正確的Node 上面,而發生資源搶奪的時候,就會觸發 Node provisioner 去跟 AWS 請求再調整Node的數量,很重要原因就是在做計算資源規劃的調整跟分配的時候需要使用到的一些觀念,把需要的資源安排到對的Node 就是這裡要做的事情。
以上的說明是基於 Machine Learning Engineer 在準備資源的時候就要先設定好規劃
這邊就舉一個例子,對MLE在安排 Taint 的最基本的設置就是 Node 對 GPU 是否需要,因為如果需要的話,則是會在設置GPU的 Node 上則是很合理,但是如果不需要的話,只需要 CPU 的計算資源,但是如果設置在 GPU Node 上 ,這時候就會顯得十分浪費錢錢。收GPU的錢跑 CPU的Task,當然在開發的時候就要很明確的定義很清楚,要用 GPU 還是CPU。
下面的內容就會針對 GPU 與 CPU 的部分 分開設置,另外可能有人會提到 AWSNodeTemplate 的話,這部分就說明一下
可以想像對Node 上面加一層保護膜,這個保護膜會過濾掉一些不被允許的 Pod 在上面。這個是設置在 node 上面的,所以可以直接使用 kubectl
的指令直接對 Node 上面增加 Taint,但是如果Pod 已經在Node 上面運行後,在設置上去的話不會直接把 Pod 移除掉,所以一開始就要先設好。
利用 Kubelctl 的指令 Example:
kubectl taint nodes <node-name> key1=value:NoSchedule
在 Karpenter 的部分 Taint 的設置就是在 Provisioner 的這邊,以下就是利用 Taint 來設置 GPU 的部分,這邊比較特別的地放就是 resources 裡面的 [nvidia.com/gpu](http://nvidia.com/gpu)
的這個部分,因爲GPU目前就是這樣設置,所以大家可能要記錄一下。
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: gpu
spec:
requirements:
- key: "karpenter.sh/capacity-type"
operator: In
values: ["spot"]
- key: "node.kubernetes.io/instance-type"
operator: In
values: ["p3.8xlarge", "p3.16xlarge"]
- key: "node-type/gpu"
operator: Exists
limits:
resources:
cpu: 1000
memory: 1000Gi
nvidia.com/gpu: 2
providerRef:
name: default
taints:
- key: "nvidia.com/gpu"
value: "true"
effect: NoSchedule
另外一般的CPU 的部分比較簡單,
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: cpu
spec:
requirements:
- key: "karpenter.k8s.aws/instance-category"
operator: In
values: ["c", "m", "r"]
- key: "karpenter.k8s.aws/instance-cpu"
operator: In
values: ["4", "8", "16", "32"]
limits:
- resources:
cpu: 1000
memory: 1000Gi
providerRef:
name: default
這裡先不設定 Taint ,其主要原因是為了後面要演示使用 Affinity 的部分,另外這邊同時也是設定為預設,如果沒有特別要求要使用GPU的話,我一率都預設丟到CPU的Node上面
如果這個 Pod 是需要使用GPU的話,配合上面設置的 Provisioner Taint ,所以這邊就會設置對應的Toleration 去呼應他
以下就是 GPU Pod 的設置部分
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: my-gpu-trainer
image: gpu-image
- resources:
limits:
nvidia.com/gpu: "1"
接著是 CPU的設置部分,這邊沒有特地使用 Toleration 在上面就是因為都沒設定所以會跑去預設的 CPU Node 上
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: myimage
resources:
requests:
memory: "128Mi"
cpu: "500m"
limits:
memory: "256Mi"
cpu: "1000m"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "karpenter.sh/capacity-type"
operator: "In"
values: ["spot"]
這兩個條件都是屬於 Overprovisioning 的內容,這個可以解決過度開車的問題
preferredDuringSchedulingIgnoredDuringExecution:
如沒滿足條件則在其他Nodes生長
requiredDuringSchedulingIgnoredDuringExecution
: 如沒滿足條件則直接創建失敗
這裡是先測試requiredDuringSchedulingIgnoredDuringExecution
。而下方是條件選擇,總共有五種條件選擇。
In
:值在某個列表中NotIn
:值不在某個列表中Gt
:值大於某個值Lt
:值小於某個值Exists
:Label存在DoesNotExist
:Label不存在如果沒有設定 Affinity 的話,就會有可能跑道 預設的 Node 上面。
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "node-type/gpu"
operator: Exists
containers:
- name: gpu-train
image: gpu-train-image
這邊就是雖然 CPU 可以讓 GPU pod 設置在上面,但是 GPU Pod 在執行的話就會沒辦法拿掉GPU 的資源,只有CPU的部分,因此設置 Affinity 可以讓Pod 設定到特定的 Node 上面
https://karpenter.sh/docs/concepts/scheduling/